using Infrastructure.Attribute;
using Infrastructure.Extensions;
using JTZY.Model.Order.Dto;
using JTZY.Model.Order;
using JTZY.Repository;
using JTZY.Service.Order.IOrderService;
using Infrastructure.Enums;
using Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using JTZY.Service.Pay.IPayService;
using Newtonsoft.Json.Linq;
using JTZY.Service.Business.IBusinessService;
using JTZY.Infrastructure.CustomException;
using JTZY.Model.Pay;
using Essensoft.Paylink.WeChatPay.V2;
using Essensoft.Paylink.WeChatPay;
using Essensoft.Paylink.WeChatPay.V2.Request;
using JTZY.Common;
using JTZY.Service.Pay;
using static JTZY.Common.GlobalEnumVars;
using JTZY.Model.Enum;
using JTZY.Model.Pay.Dto;
using WANFT.Utils;
using LaKaLaPay.Request;
using LaKaLaPay;

namespace JTZY.Service.Order
{
    /// <summary>
    /// 退款单表Service业务层处理
    /// </summary>
    [AppService(ServiceType = typeof(ICorecmsbillrefundService), ServiceLifetime = LifeTime.Transient)]
    public class CorecmsbillrefundService : BaseService<Corecmsbillrefund>, ICorecmsbillrefundService
    {

        private readonly IServiceProvider _serviceProvider;
        private readonly IWeChatPayClient _client;
        private readonly ICorecmswechatpayconfigService _weChatPayConfigServices;
        private readonly ICorecmsbillpaymentsService _billPaymentsServices;
        private readonly ICorecmsuserbalanceService _balancePayServices;
        public CorecmsbillrefundService(IServiceProvider serviceProvider, ICorecmsbillpaymentsService billPaymentsServices,
             ICorecmswechatpayconfigService weChatPayConfigServices, IWeChatPayClient client, ICorecmsuserbalanceService balancePayServices)
        {
            _serviceProvider = serviceProvider;
            _client = client;
            _weChatPayConfigServices = weChatPayConfigServices;
            _billPaymentsServices = billPaymentsServices;
            _balancePayServices = balancePayServices;
        }
        /// <summary>
        /// 查询退款单表列表
        /// </summary>
        /// <param name="parm"></param>
        /// <returns></returns>
        public PagedInfo<CorecmsbillrefundDto> GetList(CorecmsbillrefundQueryDto parm)
        {
            var predicate = QueryExp(parm);

            var response = Queryable()
                .Where(predicate.ToExpression())
                .ToPage<Corecmsbillrefund, CorecmsbillrefundDto>(parm);

            return response;
        }


        /// <summary>
        /// 获取详情
        /// </summary>
        /// <param name="RefundId"></param>
        /// <returns></returns>
        public Corecmsbillrefund GetInfo(string RefundId)
        {
            var response = Queryable()
                .Where(x => x.RefundId == RefundId)
                .First();

            return response;
        }

        /// <summary>
        /// 添加退款单表
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public Corecmsbillrefund AddCorecmsbillrefund(Corecmsbillrefund model)
        {
            return Insertable(model).ExecuteReturnEntity();
        }

        /// <summary>
        /// 修改退款单表
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public int UpdateCorecmsbillrefund(Corecmsbillrefund model)
        {
            return Update(model, true);
        }

        /// <summary>
        /// 创建退款单
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="sourceId"></param>
        /// <param name="type"></param>
        /// <param name="money"></param>
        /// <param name="aftersalesId"></param>
        /// <returns></returns>
        public async Task<WebApiCallBack> ToAdd(long userId, string sourceId, int type, decimal money, string aftersalesId, string sourceType = "0")
        {
            var jm = new WebApiCallBack();

            if (money == 0)
            {
                jm.data = jm.code = 13208;
                jm.msg = "退款金额不能为0";//GlobalErrorCodeVars.Code13208;
                return jm;
            }
            //创建退款单
            var billRefund = new Corecmsbillrefund();
            billRefund.RefundId = CommonHelper.GetSerialNumberType((int)SerialNumberType.退款单编号);
            billRefund.AftersalesId = aftersalesId;
            billRefund.Money = money;
            billRefund.UserId = userId;
            billRefund.SourceId = sourceId;
            billRefund.Type = type;
            billRefund.SourceType = sourceType;
            using var container = _serviceProvider.CreateScope();
            var afterSalesServices = container.ServiceProvider.GetService<ICorecmsbillaftersalesService>();
            var _billPaymentsServices = container.ServiceProvider.GetService<ICorecmsbillpaymentsService>();

            var billaftersale = await afterSalesServices.GetFirstAsync(a => a.AftersalesId == aftersalesId);

            //取支付成功的支付单号
            var paymentsInfo = await _billPaymentsServices.Queryable().Where(p => p.SourceId == sourceId && p.Type == type && p.Status == (int)BillPaymentsStatus.Payed).FirstAsync();
            if (paymentsInfo != null)
            {
                billRefund.PaymentCode = paymentsInfo.PaymentCode;
                billRefund.TradeNo = paymentsInfo.TradeNo;
            }
            if (billaftersale != null && billaftersale.SourceType == "1")
            {
                billRefund.PaymentCode = "creditpay";
            }

            billRefund.Status = (int)BillRefundStatus.STATUS_NOREFUND;
            billRefund.CreateTime = DateTime.Now;
            billRefund.StoreId = billaftersale.StoreId;
            //billRefund.AgentMoney = agentMoney;
            //billRefund.PId = pId;
            await InsertAsync(billRefund);

            jm.status = true;
            jm.msg = "创建成功";

            return jm;
        }

        /// <summary>
        /// 退款单去退款或者拒绝
        /// </summary>
        /// <param name="refundId">退款单id</param>
        /// <param name="status">2或者4，通过或者拒绝</param>
        /// <param name="paymentCodeStr">退款方式，如果和退款单上的一样，说明没有修改，原路返回，否则只记录状态，不做实际退款,如果为空是原路返回</param>
        /// <returns></returns>
        public async Task<WebApiCallBack> ToRefund(string refundId, int status, string paymentCodeStr = "")
        {
            var jm = new WebApiCallBack();

            var info = await Queryable().Where(p => p.RefundId == refundId && p.Status == (int)BillRefundStatus.STATUS_NOREFUND).FirstAsync();

            if (info == null)
            {
                jm.status = false;
                jm.msg = "";
                return jm;
            }

            if (paymentCodeStr == "")
            {
                paymentCodeStr = info.PaymentCode;
            }

            if (status == (int)BillRefundStatus.STATUS_REFUND)
            {

                //如果前端传过来的退款方式和退款单上的退款方式一样的话，就说明是原路返回，试着调用支付方式的退款方法,如果不一样的话，就直接做退款单的退款状态为已退款就可以了
                if (paymentCodeStr == info.PaymentCode && paymentCodeStr != "offline")
                {
                    jm = await PaymentRefund(refundId);
                }
                else
                {
                    //只修改状态，不做实际退款，实际退款线下去退。
                    await UpdateAsync(p => new Corecmsbillrefund()
                    {
                        Status = (int)BillRefundStatus.STATUS_REFUND,
                        PaymentCode = paymentCodeStr,
                        UpdateTime = DateTime.Now
                    },
                        p => p.RefundId == refundId && p.Status == (int)BillRefundStatus.STATUS_NOREFUND);
                    jm.status = true;
                }

                //退款同意，先发退款消息和钩子，下面原路返回可能失败，但是在业务上相当于退款已经退过了，只是实际的款项可能还没到账
                //发送退款消息
                if (jm.status)
                {
                    // await _messageCenterServices.SendMessage(info.userId, GlobalEnumVars.PlatformMessageTypes.RefundSuccess.ToString(), JObject.FromObject(info));

                    //退款完成后的钩子
                    jm.msg = "退款单退款成功";
                }

                return jm;
            }
            else if (status == (int)BillRefundStatus.STATUS_REFUSE)
            {
                //退款拒绝
                await UpdateAsync(
                    p => new Corecmsbillrefund()
                    {
                        Status = status,
                        PaymentCode = paymentCodeStr,
                        UpdateTime = DateTime.Now
                    },
                    p => p.RefundId == refundId && p.Status == (int)BillRefundStatus.STATUS_NOREFUND);
                jm.status = true;
                jm.msg = "退款单拒绝成功";
            }
            else
            {
                jm.status = false;
                jm.msg = "";
                return jm;
            }
            return jm;
        }

        public async Task<WebApiCallBack> PaymentRefund(string refundId)
        {

            var jm = new WebApiCallBack();

            var info = Queryable().Where(p =>
                p.RefundId == refundId && p.Status != (int)BillRefundStatus.STATUS_REFUND).First();
            if (info == null)
            {
                jm.status = false;
                jm.msg = "";
                return jm;
            }
            //using var container = _serviceProvider.CreateScope();
            //var afterSalesServices = container.ServiceProvider.GetService<ICorecmsbillaftersalesService>();
            //var _billPaymentsServices = container.ServiceProvider.GetService<ICorecmsbillpaymentsService>();
            //var _balancePayServices = container.ServiceProvider.GetService<ICorecmsuserbalanceService>();

            //取支付成功的支付单号
            var panyMentsInfo = _billPaymentsServices.Queryable().Where(p => p.SourceId == info.SourceId && p.Type == info.Type && p.Status == (int)BillPaymentsStatus.Payed).First();
            if (panyMentsInfo == null)
            {
                jm.msg = "没有找到支付成功的支付单号";
                return jm;
            }
            if (panyMentsInfo.PaymentCode != info.PaymentCode)
            {
                jm.msg = "退款单退款方式和支付方式不一样，原路退还失败";
                return jm;
            }
            //取此支付方式的信息
            //var paymentsModel = await _paymentsServices.QueryByClauseAsync(p => p.code == info.paymentCode && p.isEnable == true);
            //if (paymentsModel == null)
            //{
            //    jm.msg = GlobalErrorCodeVars.Code10050;
            //    return jm;
            //}

            //去退款
            //微信退款
            if (panyMentsInfo.PaymentCode == PaymentsTypes.wechatpay.ToString())
            {
                jm = await Refund(info, panyMentsInfo);
            }
            else if (panyMentsInfo.PaymentCode == GlobalEnumVars.PaymentsTypes.wft.ToString())
            {
                jm = await WftRefund(info, panyMentsInfo);
            }
            //支付宝退款
            //else if (panyMentsInfo.paymentCode == GlobalEnumVars.PaymentsTypes.alipay.ToString())
            //{
            //    jm = await _aliPayServices.Refund(info, panyMentsInfo);
            //}
            //余额退款
            else if (panyMentsInfo.PaymentCode == PaymentsTypes.balancepay.ToString())
            {
                //jm = await _balancePayServices.Refund(info, panyMentsInfo);
            }
            //else if (panyMentsInfo.PaymentCode == PaymentsTypes.creditpay.ToString())
            //{
            //    jm = await Refund(info, panyMentsInfo);
            //}



            if (jm.status)
            {
                var res = JsonConvert.SerializeObject(jm.data);
                Update(p => new Corecmsbillrefund() { Status = (int)BillRefundStatus.STATUS_REFUND, Memo = res }, p => p.RefundId == refundId);
            }
            else
            {
                var res = JsonConvert.SerializeObject(jm.data);
                Update(p => new Corecmsbillrefund() { Status = (int)BillRefundStatus.STATUS_FAIL, Memo = res }, p => p.RefundId == refundId);
            }

            return jm;
        }

        public async Task<WebApiCallBack> WftRefund(Corecmsbillrefund refundInfo, Corecmsbillpayments paymentInfo)
        {
            var jm = new WebApiCallBack();

            var order = await Context.Queryable<Corecmsorder>().Where(o => o.OrderId == paymentInfo.SourceId).FirstAsync();
            if (order == null)
            {
                jm.msg = "没有找到支付成功的支付单号";
                return jm;
            }


            var orderRequest = new PayInfo()
            {
                z_tp_bank_url = "https://pay.zgjindoufu.com",
                z_tp_mchno = "2024111917230667372",
                z_tp_operid = "15511",
                z_tp_termid = "202412021147",
                out_request_no = refundInfo.RefundId,
                out_trade_no = paymentInfo.PaymentId,
                z_tp_key = "88888888",
                refund_amount = refundInfo.Money.ToString("0.00")
            };

            var response = new PayRetInfo();

            WANFT_Util.Refund(orderRequest, response);

            //var response = await _client.ExecuteAsync(orderRequest, payOptions);
            if (response.code == PayReturnCode.SUCCESS.ToString())
            {
                Update(p => new Corecmsbillrefund() { Status = (int)BillRefundStatus.STATUS_REFUND, Memo = JsonConvert.SerializeObject(response) }, p => p.RefundId == refundInfo.RefundId);

                jm.status = true;
                jm.msg = "退款成功";
                jm.data = response;
            }
            else

                jm.status = false;
                jm.msg = "退款失败";
                jm.data = response;


            return jm;


        }


        /// <summary>
        ///     用户退款
        /// </summary>
        /// <param name="refundInfo">退款单数据</param>
        /// <param name="paymentInfo">支付单数据</param>
        /// <returns></returns>
        public async Task<WebApiCallBack> Refund(Corecmsbillrefund refundInfo, Corecmsbillpayments paymentInfo)
    {
        var jm = new WebApiCallBack();

        var tradeType = WeiChatPayTradeType.JSAPI.ToString();
        if (!string.IsNullOrEmpty(paymentInfo.Parameters))
        {
            var jObj = (JObject)JsonConvert.DeserializeObject(paymentInfo.Parameters);
            if (jObj != null && jObj.TryGetValue("trade_type", out var value))
                tradeType = PayHelper.GetWeiChatPayTradeType(value.ObjectToString());
        }

        var config = await _weChatPayConfigServices.Queryable().Where(p => p.MchId == paymentInfo.MchId
            && p.IsEnable == true && p.AppType == tradeType).FirstAsync();
        if (config == null)
        {
            jm.msg = "支付配置信息获取失败";
            return jm;
        }

        if (string.IsNullOrEmpty(config.RefundUrl))
        {
            jm.msg = "未获取到配置的退款通知地址";
            return jm;
        }

            if (config.Channel == "LKL")
            {
                Location_Info location_info = new Location_Info();
                location_info.request_ip = paymentInfo.Ip;
                var req = new RefundReq()
                {
                    merchant_no = config.MchId,
                    term_no = config.TermNo,
                    out_trade_no = refundInfo.RefundId,
                    origin_out_trade_no = paymentInfo.PaymentId,
                    refund_amount = Convert.ToInt32(refundInfo.Money * 100).ToString(),
                    refund_reason = "用户申请退款",
                    location_info= location_info
                };

                var payConfig = new PayConfig()
                {
                    channelAppId = config.ChannelAppId,
                    certificate = config.Certificate,
                    rsaPublicKey = config.RsaPublicKey,
                    apiKey = config.ApiKey,
                    notifyUrl = config.NotifyUrl
                };

                var response = LakalaOpenPoster.Refund(req, payConfig);
                if (response != null)
                {
                    var rspM = response.resp_data;
                    if (response.code == "BBS00000")
                    {
                        var status = (int)GlobalEnumVars.BillRefundStatus.STATUS_REFUND;
                        await UpdateAsync(p => new Corecmsbillrefund { UpdateTime = DateTime.Now, Status = status }, p => p.RefundId == refundInfo.RefundId);

                        Context.Updateable<Corecmsbillaftersales>().SetColumns(it => new Corecmsbillaftersales() { PayTime = DateTime.Now, UpdateTime = DateTime.Now, PayStatus = 1 }).Where(u => u.AftersalesId == refundInfo.AftersalesId).RemoveDataCache().ExecuteCommand();

                        //await _corecmsbillaftersalesService.UpdateAsync(p => new Corecmsbillaftersales { PayTime = DateTime.Now, UpdateTime = DateTime.Now, PayStatus = 1 }, p => p.AftersalesId == refundInfo.AftersalesId);

                        jm.status = true;
                        jm.msg = "退款成功";
                        jm.data = response;
                    }
                    else
                    {
                        jm.status = false;
                        jm.msg = "退款失败";
                        jm.data = response;
                    }
                }
            }
            else
            {
                //构建linkPay请求配置实体
                var payOptions = new WeChatPayOptions
                {
                    AppId = config.AppId,
                    MchId = config.MchId,
                    APIKey = config.ApiKey,
                    APIv3Key = config.ApiV3Key,
                    Certificate = config.Certificate,
                    RsaPublicKey = config.RsaPublicKey,
                    SubAppId = config.SubAppId,
                    SubMchId = config.SubMchId
                };

                var notifyUrl = config.RefundUrl.EndsWith("/") ? config.RefundUrl + "m-" + config.MchId : config.RefundUrl + "/m-" + config.MchId;

                var request = new WeChatPayRefundRequest
                {
                    OutRefundNo = refundInfo.RefundId,
                    TransactionId = paymentInfo.TradeNo,
                    OutTradeNo = paymentInfo.PaymentId,
                    TotalFee = Convert.ToInt32(paymentInfo.Money * 100),
                    RefundFee = Convert.ToInt32(refundInfo.Money * 100),
                    NotifyUrl = notifyUrl
                };
                var response = await _client.ExecuteAsync(request, payOptions);

                if (response.ReturnCode == WeChatPayCode.Success && response.ResultCode == WeChatPayCode.Success)
                {
                    jm.status = true;
                    jm.msg = "退款成功";
                    jm.data = response;
                }
                else
                {
                    jm.status = false;
                    jm.msg = "退款失败：" + response.ErrCodeDes;
                    jm.data = response;
                }
            }
        return jm;
    }


    /// <summary>
    /// 查询导出表达式
    /// </summary>
    /// <param name="parm"></param>
    /// <returns></returns>
    private static Expressionable<Corecmsbillrefund> QueryExp(CorecmsbillrefundQueryDto parm)
    {
        var predicate = Expressionable.Create<Corecmsbillrefund>();

        return predicate;
    }
}
}